﻿#include <iostream>
#include <sstream>
#include <fstream>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>

// 加载PEM格式的证书文件
bool loadCertificates(SSL_CTX* ctx, const char* certFile, const char* keyFile) {
    // 加载证书
    if (SSL_CTX_use_certificate_file(ctx, certFile, SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        return false;
    }

    // 加载私钥
    if (SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors_fp(stderr);
        return false;
    }

    // 检查私钥和证书是否匹配
    if (!SSL_CTX_check_private_key(ctx)) {
        std::cerr << "私钥和证书不匹配！" << std::endl;
        return false;
    }

    return true;
}

// 加载CA证书
bool loadCA(SSL_CTX* ctx, const char* caFile) {
    std::ifstream caCertFile(caFile);
    if (!caCertFile.is_open()) {
        std::cerr << "无法打开CA证书文件: " << caFile << std::endl;
        return false;
    }

    std::stringstream buffer;
    buffer << caCertFile.rdbuf();
    std::string caCertData = buffer.str();

    caCertFile.close();

    X509_STORE* store = SSL_CTX_get_cert_store(ctx);
    BIO* bio = BIO_new_mem_buf(caCertData.c_str(), caCertData.length());
    X509* caCert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
    BIO_free(bio);

    if (caCert == NULL) {
        ERR_print_errors_fp(stderr);
        return false;
    }

    X509_STORE_add_cert(store, caCert);
    X509_free(caCert);

    return true;
}

int main() {
    // 初始化Winsock库
    WSADATA wsaData;
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != 0) {
        std::cerr << "WSAStartup failed: " << result << std::endl;
        return 1;
    }

    // 创建SSL上下文
    SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());

    // 加载客户端证书和私键
    if (!loadCertificates(ctx, "D:\\Work\\Workspace\\vendor\\keys\\client.crt", "D:\\Work\\Workspace\\vendor\\keys\\client.key")) {
        WSACleanup();
        return 1;
    }

    // 加载CA证书
    if (!loadCA(ctx, "D:\\Work\\Workspace\\vendor\\keys\\ca.crt")) {
        WSACleanup();
        return 1;
    }

    // 创建TCP套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("创建套接字失败");
        WSACleanup();
        return 1;
    }

    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8091);

    // 使用inet_pton进行IP地址转换
    inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);

    // 连接服务器
    if (connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
        perror("连接服务器失败");
        closesocket(sockfd);
        WSACleanup();
        return 1;
    }

    // 使用SSL包装套接字
    SSL* ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sockfd);

    // 进行SSL握手
    if (SSL_connect(ssl) != 1) {
        ERR_print_errors_fp(stderr);
        SSL_free(ssl);
        closesocket(sockfd);
        WSACleanup();
        return 1;
    }

    std::cout << "与服务器建立了TLS连接" << std::endl;

    // 发送数据给服务器
    const char* message = "你好，服务器！\n";
    SSL_write(ssl, message, strlen(message));

    // 接收服务器响应
    char buffer[1024];
    int bytesRead = SSL_read(ssl, buffer, sizeof(buffer));
    if (bytesRead > 0) {
        buffer[bytesRead] = '\0';
        std::cout << "收到服务器响应: " << buffer << std::endl;
    }

    // 关闭SSL连接和套接字
    SSL_shutdown(ssl);
    SSL_free(ssl);
    closesocket(sockfd);

    // 清理Winsock库
    WSACleanup();

    return 0;
}